home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Freeware 31 / FreelogHS31.iso / ArgentCompta / Bankperfect / bp.exe / Scripts / Import CSV / import_csv.py < prev   
Text File  |  2007-03-24  |  25KB  |  645 lines

  1. #2.6
  2. import BP
  3. import time
  4.  
  5. CurrentYear = time.localtime()[0]
  6. Century = CurrentYear / 100
  7. MonthsPatterns = {"janvierjanuary": 1, "fevrierfebruary": 2, "marsmarch": 3, "avrilapril": 4, "maymai": 5, "juinjune": 6, "juilletjuly": 7, "aoutaugust": 8, "septembreseptember": 9, "octobreoctober": 10, "novembrenovember": 11, "decembredecember": 12}
  8. MonthsKeys = MonthsPatterns.keys()
  9.  
  10. class SCSVError(Exception): pass
  11.  
  12. class SCSV:
  13.     _NORMAL    = 0
  14.     _IN_STRING = 1
  15.  
  16.     def __init__(self, verbose = None):
  17.         self._COLUMN_SEPARATOR  = ','
  18.         self._QUOTING_DELIMITER = '"'
  19.         self._HAS_COMMENTS = None
  20.         self._IGNORE_EMPTY_LINES = None
  21.         self._STRIP_CELLSPACES = None
  22.         self._currentLine = -1
  23.         self._currentRow  = -1
  24.         self.file = None
  25.         self.lineiterator = None
  26.  
  27.     def opencsv(self, filename, separator):
  28.         self._COLUMN_SEPARATOR  = separator
  29.         self._QUOTING_DELIMITER = '"'
  30.         try:
  31.           file = open(filename, 'r')
  32.         except:
  33.           raise SCSVError, "Impossible de lire le fichier %s." % filename
  34.         self.lineiterator = file.xreadlines()
  35.         self._currentLine = 0
  36.         self._currentRow  = 0
  37.  
  38.     def close(self):
  39.         self.lineiterator = None
  40.         self.file.close()
  41.         self.file = None
  42.         self._currentLine = -1
  43.         self._currentRow  = -1
  44.  
  45.     def nextrow(self):
  46.       if self.lineiterator == None:
  47.         raise SCSVError, "Impossible de lire la ligne. Le fichier n'est pas ouvert en lecture."
  48.       try:
  49.         line = self.lineiterator.next()
  50.         self._currentLine += 1
  51.       except StopIteration:
  52.         return None
  53.       else:
  54.         currentrow = line
  55.         ( columns, requiresmore, ignore ) = self._parsecsvline(currentrow)
  56.         if ignore: currentrow = ''
  57.         while requiresmore:
  58.             try:
  59.                 line = self.lineiterator.next()
  60.                 self._currentLine += 1
  61.             except StopIteration:
  62.                 self._currentRow += 1
  63.                 return columns
  64.             else:
  65.                 currentrow += line
  66.                 ( columns, requiresmore, ignore ) = self._parsecsvline(currentrow)
  67.                 if ignore: currentrow = ''
  68.         self._currentRow += 1
  69.         return columns
  70.  
  71.     def getallrows(self):
  72.       allrows = []
  73.       currentrow = self.nextrow()
  74.       while currentrow:
  75.         allrows.append(currentrow)
  76.         currentrow = self.nextrow()
  77.       return allrows
  78.  
  79.     def _parsecsvline(self, line):
  80.         rawsplit = line.split(self._COLUMN_SEPARATOR)
  81.         cleansplit = []
  82.         i = 0
  83.  
  84.         if self._HAS_COMMENTS and line.startswith('#'): return (None, 1, 1)
  85.         if self._IGNORE_EMPTY_LINES and len(line.strip()) == 0: return (None, 1, 1)
  86.  
  87.         state = self._NORMAL
  88.         while i < len(rawsplit):
  89.           cell = rawsplit[i]
  90.           if state == self._NORMAL:
  91.             if cell.lstrip().startswith(self._QUOTING_DELIMITER):
  92.               state = self._IN_STRING
  93.               if cell.rstrip().endswith(self._QUOTING_DELIMITER):
  94.                 state = self._NORMAL
  95.                 cleansplit.append( cell.strip()[1:-1].replace(self._QUOTING_DELIMITER * 2 ,self._QUOTING_DELIMITER))
  96.               else: cleansplit.append(cell.lstrip()[1:])
  97.             else: cleansplit.append(cell)
  98.           else:
  99.             if cell.rstrip().endswith(self._QUOTING_DELIMITER):
  100.               state = self._NORMAL
  101.               cleansplit[-1] = (cleansplit[-1] + self._COLUMN_SEPARATOR + cell.rstrip()[:-1]).replace(self._QUOTING_DELIMITER * 2,self._QUOTING_DELIMITER)
  102.             else: cleansplit[-1] += self._COLUMN_SEPARATOR + cell
  103.           i += 1
  104.         if len(cleansplit[-1]) > 0:
  105.           if cleansplit[-1][-1] in ('\n','\r'): cleansplit[-1] = cleansplit[-1][:-1]
  106.         if self._STRIP_CELLSPACES: return (  [i.strip() for i in cleansplit], state, None)
  107.         else: return (cleansplit, state, None)
  108.  
  109. #___________________________________________________________________________________
  110.  
  111. CIndexes = {}
  112. CtgPatt = []
  113. categs1 = []
  114. categs2 = []
  115.  
  116. d = {}
  117. ko = "└┴┬├─┼╞╟╚╔╩╦╠═╬╧╤╥╙╘╒╓┘┌█▄▌▀αßΓπΣσµτΦΘΩδ∞φε∩±≥≤⌠⌡÷∙·√ⁿ² ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  118. ok = "aaaaaaaceeeeiiiinooooouuuuybaaaaaaaceeeeiiiinooooouuuuyyabcdefghijklmnopqrstuvwxyz"
  119. [d.setdefault(a, b) for a, b in zip(ko, ok)]
  120. PatternTable = "".join([d.get(chr(i), chr(i)) for i in range(256)])
  121.  
  122. def create_columns_from_crlf(lines):
  123.   cols = {}
  124.   for line in lines:
  125.     for i, col in enumerate(line):
  126.       if "\n" in col or "\r" in col: cols[i] = 1
  127.   cols = cols.keys()
  128.   cols.sort()
  129.   
  130.   lines2 = []
  131.   for line in lines:
  132.     for col in cols:
  133.       if col > len(line) - 1: CellToSplit = ""
  134.       else: CellToSplit = line[col]
  135.       if "\n" in CellToSplit or "\r" in CellToSplit:
  136.         CellToSplit = CellToSplit.replace("\r\n", "\n")
  137.         CellToSplit = CellToSplit.replace("\r", "\n")
  138.         cells = CellToSplit.split("\n")
  139.         if len(cells) > 2: cells = cells[:1] + [" ".join(cells[1:])]
  140.       else: cells = [CellToSplit, ""]
  141.       line = line[:col] + cells + line[col + 1:]
  142.     lines2.append(line)
  143.   return lines2
  144.  
  145. def loadfile(path, sep):
  146.   f = SCSV()
  147.   if sep == "TAB": sep = "\t"
  148.   f.opencsv(path, sep)
  149.   return f.getallrows()
  150.  
  151. def Pattern(v):
  152.   return v.translate(PatternTable, " -.,;:/!?'_=()")
  153.  
  154. def DoIndexCategs():
  155.   global CIndexes, CtgPatt, categs1, categs2
  156.   CIndexes = {}
  157.   for i, c in enumerate(BP.CategName):
  158.     CIndexes[i] = int(c[:c.find("=")])
  159.   CtgPatt = [Pattern(c) for c in BP.CategName]
  160.   categs1 = [(CtgPatt[i], i) for i in range(len(CtgPatt)) if BP.CategParent[i] == i]
  161.   categs2 = [(CtgPatt[i], i, BP.CategParent[i]) for i in range(len(CtgPatt)) if BP.CategParent[i] != i]
  162.  
  163. DoIndexCategs()
  164.  
  165. Acc = BP.AccountCurrent()
  166. dateFmts, Seps, mapping, Show = ["JMA", "MJA", "AMJ"], [";", ",", "\t"], [0, 0, 0, 0, 0, 0, 0, 0, 0], [50, 100, 500]
  167. fields = ["Date", "Mode", "Tiers", "DΘtails", "CatΘgorie", "Sous-catΘgorie", "Montant", "DΘbit", "CrΘdit"]
  168. MrkList = ["Non PointΘ", "PointΘ", "RapprochΘ"]
  169. l, b, CC, cs, cb = "TLabel", "TButton", CreateComponent, "csDropDownList", "TComboBox"
  170. CSV = []
  171.  
  172. def GetBounds():
  173.   s = EStart.Text
  174.   if s.isdigit(): sLine = int(s)
  175.   else: sLine = 2
  176.   if sLine < 1: sLine = 1
  177.  
  178.   s = EEnd.Text
  179.   if s.isdigit(): eLine = int(s)
  180.   else: eLine = 0
  181.   if eLine < sLine: eLine = 0
  182.   return sLine, eLine
  183.  
  184. def Import(S):
  185.  
  186.   global DateFmt
  187.   for i in range(len(mapping)): mapping[i] = Combos[i].ItemIndex
  188.  
  189.   if mapping[0] <= 0: s = "La date n'est pas spΘcifiΘe !"
  190.   elif (mapping[6] > 0 and mapping[7] > 0) or (mapping[6] > 0 and mapping[8] > 0): s = "DΘbit/CrΘdit OU Montant !"
  191.   elif mapping[6] <= 0 and (mapping[7] <= 0 or mapping[8] <= 0): s = "Le montant n'est pas spΘcifiΘ !"
  192.   else: s = ""
  193.   if s:
  194.     LMsg.Caption = s
  195.     return
  196.  
  197.   mark = CBMark.ItemIndex
  198.   for i in range(len(MrkList)):
  199.    if mark == MrkList[i]: mark = i
  200.  
  201.   sLine, eLine = GetBounds()
  202.  
  203.   DateFmt = dateFmts[CBDate.ItemIndex]
  204.   records, min_date = linestodict(CSV, Seps[CBSep.ItemIndex], sLine, eLine)
  205.   currLines, Light = CurrentLines(min_date)
  206.  
  207.   idx = CBDup.ItemIndex
  208.   Count = len(records)
  209.   i = 0
  210.   for r in records:
  211.     line = FmtLine(r)
  212.     i += 1
  213.     date, mode, tier, info, catg, mont = r.get("Date", ""), r.get("Mode", ""), r.get("Tiers", ""), r.get("DΘtails", ""), r.get("CatΘgorie", ""), r.get("Montant", "")
  214.     if not IsDate(date): report["Dates incorrectes"].append(line)
  215.     elif mont == "" or abs(mont) < 0.0001: report["Montants incorrects"].append(line)
  216.     else:
  217.       insertDupl, idx = TestDup(i, Count, idx, currLines, Light, (date, mode, tier, info, mont), date, simplecheck(mode), mont, line)
  218.       if insertDupl == "ko": continue
  219.       if catg == "": catg = -1
  220.       mode, tier, info = SCheckNum(mode, tier, info)
  221.       count1 = BP.OperationCount[Acc]
  222.       date = Date2Str(date)
  223.       BP.LineAdd(Acc, date, mode, tier, info, catg, mont, mark)
  224.       count2 = BP.OperationCount[Acc]
  225.       if count2 == count1: report["Lignes refusΘes"].append(line)
  226.       else: report["OpΘrations importΘes"].append(line)
  227.  
  228.   BP.AccountRefreshScreen()
  229.   MRes.Lines.Text = Errors(report)
  230.   FF.ShowModal()
  231.   F0.Close()
  232.  
  233. def draw(S, ACol, ARow, R, State):
  234.   cv = S.Canvas
  235.   if "gdSelected" in State: cv.Brush.Color = 0x00dec5b9
  236.   elif ARow > 0 and ARow % 2 == 0: cv.Brush.Color = 0x00f5f5f5
  237.   cv.FillRect(R)
  238.  
  239.   try:
  240.     if ARow == 0:
  241.       if ACol == 0: s = "n░"
  242.       else: s = "Col. %d" %ACol
  243.       cv.Font.Style = ["fsBold"]
  244.     else: s = cells[ARow - 1][ACol]
  245.   except:
  246.     s = ""
  247.  
  248.   if ACol == 0 and ARow > 0: cv.Font.Color = 0x000000CC
  249.   else: cv.Font.Color = 0x00000000
  250.   if s != "": cv.TextRect(R, R.Left + 3, R.Top + 5, s)
  251.   cv.Brush.Style = 1
  252.  
  253. def Resize(S):
  254.   Grid.DefaultColWidth = (Grid.Width - 40) / Grid.ColCount
  255.  
  256. def guess(mapping, title_line, sep):
  257.   titles = [Pattern(t) for t in title_line]
  258.   cols = range(len(titles))
  259.   fs = [["date"], ["mode", "type"], ["tiers", "libelle"], ["details", "note", "notes"], ["categorie", "categ"], ["souscategorie", "sscategorie", "sscateg", "souscateg", "scateg", "scategorie"], ["montant", "montanteuro", "montanteuros"], ["debit", "debiteuros", "debiteuro"], ["credit", "crediteuro", "crediteuros"]]
  260.   for i in range(len(fs)):
  261.     possibles = fs[i]
  262.     for col in cols:
  263.       if titles[col] in possibles:
  264.         mapping[i] = col + 1
  265.         break
  266.  
  267. def FillGrid(S):
  268.   global CSV, cells, mapping
  269.   CSV = loadfile(Path, CBSep.Text)
  270.   if CCrlf.Checked: CSV = create_columns_from_crlf(CSV)
  271.   i = CBShow.ItemIndex
  272.   if i < 3: L = CSV[:Show[i]]
  273.   else: L = CSV
  274.   #s = Seps[CBSep.ItemIndex]
  275.   cells = [["%d" %(i + 1)] + l for i, l in enumerate(L)]
  276.   cols = max([len(l) for l in cells])
  277.   Grid.ColCount, Grid.RowCount = cols, len(cells)
  278.   
  279.   sLine, eLine = GetBounds()
  280.   if sLine <= 1: sLine = 2
  281.   guess(mapping, CSV[sLine - 2], Seps[CBSep.ItemIndex])
  282.   for i, cb in enumerate(Combos):
  283.     cb.Items.Text = "--\n" + "\n".join([str(j) for j in range(1, cols)])
  284.     cb.ItemIndex = mapping[i]
  285.   Resize(S)
  286.  
  287.  
  288. F0 = CC("TForm", None)
  289. F0.SetProps(Position = "poMainFormCenter", Width=800, Height=495, Caption = "ParamΦtres de l'import")
  290. CC(l, F0).SetProps(Parent=F0, Left=20, Top=25, Caption="Date / SΘpar. :")
  291. CC(l, F0).SetProps(Parent=F0, Left=20, Top=50, Caption="Doublons :")
  292. CC(l, F0).SetProps(Parent=F0, Left=20, Top=75, Caption="PremiΦre/dern. ligne :")
  293. CC(l, F0).SetProps(Parent=F0, Left=20, Top=148, Caption="Pointage :")
  294. LFld = CC(l, F0)
  295. LFld.SetProps(Parent=F0, Left=20, Top=177, Caption="Champ")
  296. LMap = CC(l, F0)
  297. LMap.SetProps(Parent=F0, Left=130, Top=177, Width=45, Caption="Colonne")
  298. LMsg = CC(l, F0)
  299. LMsg.SetProps(Parent=F0, Left=20, Top=432)
  300. LMsg.Font.Color = 0x000000CC
  301. CBDate = CC(cb, F0)
  302. CBDate.SetProps(Parent=F0, Left=130, Top=20, Width=48, Style=cs)
  303. CBDate.Items.Text = "\n".join(dateFmts)
  304. CBDate.ItemIndex = 0
  305. CBSep = CC(cb, F0)
  306. CBSep.SetProps(Parent=F0, Left=183, Top=20, Width=48, Style=cs, OnChange=FillGrid)
  307. CBSep.Items.Text = ";\n,\nTAB"
  308. CBSep.ItemIndex = 0
  309. CBDup = CC(cb, F0)
  310. CBDup.SetProps(Parent=F0, Left=130, Top=45, Width=100, Style=cs)
  311. CBDup.Items.Text = "Tout accepter\nTout refuser\nDemander"
  312. CBDup.ItemIndex = 2
  313. EStart = CC("TEdit", F0)
  314. EStart.SetProps(Parent=F0, Left=130, Top=70, Width=48, Text="2", OnExit=FillGrid)
  315. EEnd = CC("TEdit", F0)
  316. EEnd.SetProps(Parent=F0, Left=183, Top=70, Width=48)
  317. CCrlf = CC("TCheckBox", F0)
  318. CCrlf.SetProps(Parent=F0, Left=20, Top=100, Width=200, Caption="CrΘer une colonne si retour α la ligne", Checked=0, OnClick=FillGrid)
  319. CCtgs = CC("TCheckBox", F0)
  320. CCtgs.SetProps(Parent=F0, Left=20, Top=122, Width=200, Caption="CrΘer les catΘgories manquantes", Checked=0)
  321. CBMark = CC(cb, F0)
  322. CBMark.SetProps(Parent=F0, Left=130, Top=144, Width=100, Style=cs)
  323. CBMark.Items.Text = "\n".join(MrkList)
  324. CBMark.ItemIndex = 0
  325. Grid = CC("TDrawGrid", F0)
  326. Grid.SetProps(Parent=F0, Left=250, Top=20, Width=525, Height=397, Anchors=["AkLeft", "akTop", "akRight", "akBottom"], FixedCols=0, OnDrawCell=draw, Options = ["goFixedHorzLine", "goVertLine", "goDrawFocusSelected", "goRowSelect", "goThumbTracking"])
  327. CBShow = CC(cb, F0)
  328. CBShow.SetProps(Parent=F0, Left=250, Top=429, Width=125, Style=cs, Anchors=["akLeft", "akBottom"], OnChange=FillGrid)
  329. CBShow.Items.Text = "Afficher 50 lignes\r\nAfficher 100 lignes\r\nAfficher 500 lignes\r\nTout afficher"
  330. CBShow.ItemIndex = 0
  331. CC(b, F0).SetProps(Parent=F0, Left=625, Top=427, Width=70, Height=25, Caption="Annuler", Cancel=1, Anchors=["akRight", "akBottom"], ModalResult=2)
  332. CC(b, F0).SetProps(Parent=F0, Left=705, Top=427, Width=70, Height=25, Caption="Importer", Default=1, OnClick=Import, Anchors=["akRight", "akBottom"])
  333. F0.OnResize=Resize
  334.  
  335. FDup = CC("TForm", None)
  336. FDup.SetProps(Width=400, Height=390, Position="poMainFormCenter", BorderStyle="bsSingle", BorderIcons=["biSystemMenu"], Caption="DΘtection de doublons")
  337. l0 = CC(l, FDup)
  338. l0.SetProps(Parent=FDup, Left=20, Top=20)
  339. l1 = CC(l, FDup)
  340. l1.SetProps(Parent=FDup, Left=20, Top=60, Caption="Ligne α insΘrer :")
  341. l2 = CC(l, FDup)
  342. l2.SetProps(Parent=FDup, Left=20, Top=190, Caption="Ligne existante :")
  343. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=80, Caption="Date :")
  344. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=100, Caption="Mode :")
  345. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=120, Caption="Tiers :")
  346. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=140, Caption="DΘtails :")
  347. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=160, Caption="Montant :")
  348. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=210, Caption="Date :")
  349. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=230, Caption="Mode :")
  350. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=250, Caption="Tiers :")
  351. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=270, Caption="DΘtails :")
  352. CC(l, FDup).SetProps(Parent=FDup, Left=40, Top=290, Caption="Montant :")
  353. lD = CC(l, FDup)
  354. lD.SetProps(Parent=FDup, Left=120, Top=80)
  355. lM = CC(l, FDup)
  356. lM.SetProps(Parent=FDup, Left=120, Top=100)
  357. lT = CC(l, FDup)
  358. lT.SetProps(Parent=FDup, Left=120, Top=120)
  359. lI = CC(l, FDup)
  360. lI.SetProps(Parent=FDup, Left=120, Top=140)
  361. lA = CC(l, FDup)
  362. lA.SetProps(Parent=FDup, Left=120, Top=160)
  363. LD = CC(l, FDup)
  364. LD.SetProps(Parent=FDup, Left=120, Top=210)
  365. LM = CC(l, FDup)
  366. LM.SetProps(Parent=FDup, Left=120, Top=230)
  367. LT = CC(l, FDup)
  368. LT.SetProps(Parent=FDup, Left=120, Top=250)
  369. LI = CC(l, FDup)
  370. LI.SetProps(Parent=FDup, Left=120, Top=270)
  371. LA = CC(l, FDup)
  372. LA.SetProps(Parent=FDup, Left=120, Top=290)
  373. lD.Font.Color = lM.Font.Color = lT.Font.Color = lI.Font.Color = lA.Font.Color = LD.Font.Color = LM.Font.Color = LT.Font.Color = LI.Font.Color = LA.Font.Color = 0x00CC0000
  374. CC(b, FDup).SetProps(Parent=FDup, Left=40, Top=320, Width=75, Height=25, Caption="Oui", ModalResult=6)
  375. CC(b, FDup).SetProps(Parent=FDup, Left=120, Top=320, Width=75, Height=25, Caption="Non", ModalResult=7)
  376. CC(b, FDup).SetProps(Parent=FDup, Left=200, Top=320, Width=75, Height=25, Caption="Toutes", ModalResult=10)
  377. CC(b, FDup).SetProps(Parent=FDup, Left=280, Top=320, Width=75, Height=25, Caption="Aucune", ModalResult=9)
  378.  
  379. FF = CC("TForm", None)
  380. FF.SetProps(Width=640, Height=450, Position="poMainFormCenter", BorderStyle="bsSingle", BorderIcons=["biSystemMenu"], Caption="RΘsultat de l'import")
  381. CC(b, FF).SetProps(Parent=FF, Left=270, Top=370, Width=100, Height=25, Caption="Fermer", ModalResult=1, Cancel=1, Default=1)
  382. MRes = CC("TMemo", FF)
  383. MRes.SetProps(Parent=FF, Left=30, Top=30, Width=580, Height=350, Anchors=["akTop","akLeft", "akRight", "akBottom"], WordWrap=0, Readonly=1)
  384.  
  385. l0.Font.Style = l1.Font.Style = l2.Font.Style = LMap.Font.Style = LMsg.Font.Style = LFld.Font.Style = ["fsBold"]
  386. F0.Font.Name = FF.Font.Name = FDup.Font.Name = "Tahoma"
  387.  
  388. def Date2Str(d):
  389.   y, m, d = d
  390.   if y < 100: y += 2000
  391.   return "%02d/%02d/%04d" %(d, m, y)
  392.  
  393. def Errors(report):
  394.   ok = 0
  395.   ko = 0
  396.   lines = []
  397.   for key in report.keys():
  398.    l = report[key]
  399.    num = len(l)
  400.    if num == 0: continue
  401.    if key == "OpΘrations importΘes": ok += num
  402.    else: ko += num
  403.    l = ["  %s" %s for s in l]
  404.    lines.append("%s (%d) :\r\n\r\n%s" %(key, num, "\r\n".join(l)))
  405.  
  406.   total = ok + ko
  407.   if total == 0:
  408.    s = "Il n'y a aucune ligne α importer depuis le fichier"
  409.   else:
  410.    if ko == 0:
  411.      if total == 1: s = "L'opΘration contenue dans le fichier CSV a ΘtΘ importΘe sans erreurs"
  412.      else: s = "Les %d opΘrations contenues dans le fichier CSV ont ΘtΘ importΘes sans erreurs" %total
  413.    elif ok == 0: s = "Aucune ligne n'a pu Ωtre importΘe"
  414.    else:
  415.      if ok == 1: s = "Une opΘration sur %d a ΘtΘ importΘe" %(total)
  416.      else: s = "%d opΘrations sur %d ont ΘtΘ importΘes" %(ok, total)
  417.  
  418.    s = "%s\r\n\r\n%s" %(s, "\r\n\r\n".join(lines))
  419.   return s
  420.  
  421. def IsDate(t):
  422.   try:
  423.     y, m, d = t
  424.     if (m == 2) and (y % 4 == 0) and ( (y % 100 != 0) or (y % 400 == 0) ): Max = 29
  425.     else: Max = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][m - 1]
  426.     return m > 0 and m < 13 and d > 0 and d <= Max
  427.   except:
  428.     return 0
  429.  
  430. def FmtLine(dic):
  431.   s = []
  432.   for key in dic.keys():
  433.    v = dic[key]
  434.    if key == "Date": v = Date2Str(v)
  435.    s.append("%s : %s" %(key, v))
  436.    s.sort()
  437.   return ",  ".join(s)
  438.  
  439. def ParseMonth(s):
  440.   if s.isdigit(): return int(s)
  441.   s = Pattern(s)
  442.   for key in MonthsKeys:
  443.     if s in key: return MonthsPatterns[key]
  444.   return None
  445.  
  446. def ParseDay(s):
  447.   if s.isdigit(): return int(s)
  448.   return None
  449.  
  450. def ParseYear(s):
  451.   if s.isdigit():
  452.     v = int(s)
  453.     if v < 100: v += 100 * Century
  454.     return v
  455.   return None
  456.  
  457. def Str2Date(d):
  458.   Seps = "/-' .;"
  459.   d = d.replace("-", "/").replace(".", "/").replace("'", "/").replace(",", "/").replace(" ", "/")
  460.   while "//" in d: d = d.replace("//", "/")
  461.   s = d.split("/")
  462.   if len(s) == 2 and DateFmt in ["JMA", "MJA"]: s += [str(CurrentYear)]
  463.   if len(s) != 3: return None
  464.   y, m, d = ParseYear(s[DateFmt.find("A")]), ParseMonth(s[DateFmt.find("M")]), ParseDay(s[DateFmt.find("J")])
  465.   if y is None or m is None or d is None: return None
  466.   return y, m, d  
  467.  
  468. def Str2Float(value):
  469.   s = value
  470.   s = s.replace("$", "").replace(" ", "").replace("Ç", "").replace("F", "").replace(",", ".")
  471.   if "." in s:
  472.    l = s.split(".")
  473.    s = "%s.%s" %( "".join(l[:-1]), l[-1] )
  474.   try:
  475.    f = float(s)
  476.   except:
  477.    return None
  478.   return f
  479.  
  480. def GetCtg(cat, sub):
  481.   cat, sub = cat.strip(), sub.strip()
  482.   if cat == "" and sub == "": return -1
  483.  
  484.   cat, sub = Pattern(cat), Pattern(sub)
  485.   if cat == "" and sub == "": return -1
  486.  
  487.   if cat == "" or sub == "":
  488.    t = cat + sub
  489.    if t in CtgPatt: return CIndexes.get(CtgPatt.index(t), -1)
  490.    else:
  491.      for i in range(len(CtgPatt)):
  492.        c = CtgPatt[i]
  493.        if t in c or c in t > -1: return i
  494.   else:
  495.    match1 = [c for c in categs1 if cat in c[0] or c[0] in cat]
  496.    match2 = [c for c in categs2 if sub in c[0] or c[0] in sub]
  497.    if len(match1) == 0 and len(match2) == 0: t = cat
  498.    else:
  499.      if len(match1) == 0: return CIndexes.get(match2[0][1], -1)
  500.      if len(match2) == 0: return CIndexes.get(match1[0][1], -1)
  501.  
  502.      parent_indexes = [m[1] for m in match1]
  503.      for m in match2:
  504.        if m[2] in parent_indexes: return CIndexes.get(m[1], -1)
  505.      return CIndexes.get(match2[0][1], -1)
  506.  
  507.   if CCtgs.Checked:
  508.     BP.CategAdd(t, 0)
  509.     DoIndexCategs()
  510.     s = BP.CategName[BP.CategCount() - 1]
  511.     return int(s[:s.find("=")])
  512.   return -1
  513.  
  514. def getmode(value, sign):
  515.   value = value.strip()
  516.   if value != "":
  517.    if sign == -1 and value.isdigit(): return "Chq %s" %value
  518.  
  519.    v = Pattern(value)
  520.    if sign == 1: fmodes = {"Versement": ["vers", "esp"], "DΘp⌠t de chΦque": ["rem", "dep", "ch"], "Virement reτu": ["vir", "vrm", "vrt"]}
  521.    else: fmodes = {"Carte": ["fac", "cb", "car", "achatcarte", "achatcb"], "Retrait DAB": ["ret", "dab", "distrib", "automat"], "ChΦque Θmis": ["ch"], "PrΘlΦvement": ["pr"], "Virement Θmis": ["vir", "vrm", "vrt"], "TIP": ["tip"]}
  522.  
  523.    for m in fmodes.keys():
  524.      fpatterns = fmodes[m]
  525.      for fpattern in fpatterns:
  526.        if v.find(fpattern) == 0:
  527.          if m == "ChΦque Θmis":
  528.            v = value.split(" ")[-1].split(".")[-1].split("░")[-1].split("Q")[-1].split("E")[-1].split("H")[-1]
  529.            if v.isdigit(): return "Chq %s" %v
  530.          return m
  531.   if sign == 1: return "Virement reτu"
  532.   else: return "PrΘlΦvement"
  533.  
  534. def linetodict(cols):
  535.   d = {}
  536.   for i in range(len(fields)):
  537.     field = fields[i]
  538.     num_col = mapping[i] - 1
  539.     if num_col == -1: continue
  540.     if num_col >= len(cols): value = ""
  541.     else: value = cols[num_col]
  542.     if len(value) > 2 and value[0] == '"' and value[-1] == '"': value = value[1:-1]
  543.     if "\n" in value: value = value.replace("\n", " ")
  544.     while "  " in value: value = value.replace("  ", " ")
  545.     if field == "Date": value = Str2Date(value)
  546.     elif (field == "Montant" or field == "DΘbit" or field == "CrΘdit") and value != "":
  547.       value = Str2Float(value)
  548.       if field == "DΘbit": value = -abs(value)
  549.       elif field == "CrΘdit": value = abs(value)
  550.       if value != None:
  551.         if value > 0: sign = 1
  552.         elif value < 0: sign = -1
  553.         else: sign = 0
  554.       field = "Montant"
  555.     if value != None and field != "DΘbit" and field != "CrΘdit": d[field] = value
  556.  
  557.   d["CatΘgorie"] = GetCtg(d.get("CatΘgorie", ""), d.get("Sous-catΘgorie", ""))
  558.   try:
  559.    if sign != 0: d["Mode"] = getmode(d.get("Mode", ""), sign)
  560.    return d
  561.   except:
  562.    return None
  563.  
  564. def linestodict(CSV, sep, sLine, eLine):
  565.   global report
  566.   report = {"OpΘrations importΘes" : [], "Dates incorrectes" : [], "Montants incorrects" : [], "Enregistrements incorrects" : [], "Lignes refusΘes" : [], "Doublons" : []}
  567.   min_date, records = (3000, 12, 31), []
  568.   if eLine > 0 and eLine >= sLine: CSV = CSV[sLine - 1:eLine]
  569.   else: CSV = CSV[sLine - 1:]
  570.  
  571.   for l in CSV:
  572.    if "".join(l).strip() == "": continue
  573.    try: record = linetodict(l)
  574.    except: record = None
  575.  
  576.    if record != None:
  577.      if not record.has_key("Date"): report["Dates incorrectes"].append(l)
  578.      elif not record.has_key("Montant"): report["Montants incorrects"].append(l)
  579.      else:
  580.        y, m, d = record["Date"]
  581.        if y < 100: y += 2000
  582.        record["Date"] = (y, m, d)
  583.        if (y, m, d) < min_date: min_date = (y, m, d)
  584.        records.append(record)
  585.    else: report["Enregistrements incorrects"].append(l)
  586.  
  587.   return records, min_date
  588.  
  589. def TestDup(N, T, ask, Lines, Light, R, d, m, v, line):
  590.   if ask == 0: res = "ok", ask
  591.   elif not (d, m, v) in Light: res = "ok", ask
  592.   elif ask == 1: res = "ko", ask
  593.   else:
  594.     i = Light.index((d, m, v))
  595.     l = Lines[i]
  596.     lD.Caption, lM.Caption, lT.Caption, lI.Caption, lA.Caption = Date2Str(R[0]), R[1], R[2], R[3], R[4]
  597.     LD.Caption, LM.Caption, LT.Caption, LI.Caption, LA.Caption = Date2Str(l[0]), l[1], l[3], l[4], l[2]
  598.     l0.Caption = "La ligne %d/%d ressemble α une ligne existante.\nSouhaitez-vous l'insΘrer ?" %(N, T)
  599.     i = FDup.ShowModal()
  600.     res = {6: ("ok", ask), 10: ("ok", 0), 7: ("ko", ask), 9: ("ko", 1)}[i]
  601.  
  602.   if res[0] == "ko": report["Doublons"].append(line)
  603.   return res
  604.  
  605. def simplecheck(s):
  606.   return [s, "ChΦque Θmis"][s.find("Chq") == 0]
  607.  
  608. def CurrentLines(from_date):
  609.   i = Acc
  610.   lines = zip(BP.OperationDate[i], BP.OperationMode[i], BP.OperationAmount[i], BP.Operationthirdparty[i], BP.OperationDetails[i])
  611.   lines = [((int(dt[6:10]), int(dt[3:5]), int(dt[0:2])), mode, value, people, details) for (dt, mode, value, people, details) in lines if (int(dt[6:10]), int(dt[3:5]), int(dt[0:2])) >= from_date]
  612.   lines_search = [(l[0], simplecheck(l[1]), l[2]) for l in lines]
  613.   return lines, lines_search
  614.  
  615. def SCheckNum(mode, tier, info):
  616.   if mode == "ChΦque Θmis" and tier != "":
  617.     num = tier.split("░")[-1].split(" ")[-1]
  618.     if num.isdigit(): mode = "Chq %s" %num
  619.     else:
  620.       num = info.split("░")[-1].split(" ")[-1]
  621.       if num.isdigit(): mode = "Chq %s" %num
  622.  
  623.   if mode.find("Chq ") == 0:
  624.     if info == "": info = "n░%s" %(mode[4:])
  625.     else: info = "n░%s %s" %(mode[4:], info)
  626.     mode = "ChΦque Θmis"
  627.  
  628.   return mode, tier, info
  629.  
  630. Combos = []
  631. Path = BP.OpenDialog("Choisissez le fichier α importer", "\\", ".csv", "Comma Separated Values (*.CSV)|*.csv|VidΘoposte (*.TSV)|*.tsv")
  632. if Path != "":
  633.   if Path[-3:] == "tsv": mapping, EStart.Text, CBSep.ItemIndex = [1, 2, 2, 0, 0, 0, 3, 0, 0], "9", 2  
  634.   cols = "--\n" + "\n".join([str(i) for i in range(1, Grid.ColCount)])
  635.   FillGrid(None)
  636.  
  637.   for i in range(len(mapping)):
  638.     CC("TLabel", F0).SetProps(Parent=F0, Left=20, Top=i * 25 + 200, Caption=fields[i])
  639.     cb = CC("TComboBox", F0)
  640.     cb.SetProps(Parent=F0, Left=130, Width=50, Top=i * 25 + 197, Style=cs)
  641.     cb.Items.Text = cols
  642.     cb.ItemIndex = mapping[i]
  643.     Combos.append(cb)
  644.  
  645.   F0.ShowModal()